package message;

import java.io.IOException;

import message.types.data.AddDataRequest;
import message.types.data.GetAllDatasAnswer;
import message.types.data.GetLastDataAnswer;
import message.types.message.RejectedRequest;
import message.types.none.GetAllDatasRequest;
import message.types.none.GetLastDataRequest;
import message.types.none.NewDataNotification;
import message.types.stalker.CreateRoomSuccessAnswer;
import message.types.stalker.LogOffNotification;
import message.types.stalker.LoginSuccessAnswer;
import message.types.stalker.RegisterRequest;
import message.types.stalkerstring.GetRoomFromNameAnswer;
import message.types.stalkerstring.GetUserFromNameAnswer;
import message.types.string.CreatePrivatePersistentRoomRequest;
import message.types.string.CreateRoomRequest;
import message.types.string.GetRoomFromNameRequest;
import message.types.string.GetUserFromNameRequest;
import message.types.string.LoginRequest;
import message.types.stringstring.LoginFailedAnswer;
import message.types.unique.EmptyMessage;
import message.types.unique.RoomInvitation;
import network.e2e.FrameReader;
import network.e2e.FrameWriter;
import stalker.Stalker;
import stalker.StalkerParser;

/**
 * Parser from the net that can retrieve or send a corresponding object
 */

public class MessageParser {
  
  /**
   * String IDs for the messages
   */
  private final static String ADD_DATA_REQUEST = "MSG_ADDDATAREQ";
  private final static String GET_LAST_DATA_REQUEST = "MSG_GETLASTREQ";
  private final static String GET_LAST_DATA_ANSWER = "MSG_GETLASTANS";
  private final static String REGISTER_REQUEST = "MSG_REGISTERREQ";
  private final static String LOGIN_REQUEST = "MSG_LOGINREQ";
  private final static String LOGIN_SUCCESS_ANSWER = "MSG_LOGINOKANS";
  private final static String LOGIN_FAILED_ANSWER = "MSG_LOGINFAILANS";
  private final static String CREATE_ROOM_REQUEST = "MSG_CRTROOMANS";
  private final static String CREATE_PRIVATE_PERSISTENT_ROOM_REQUEST = "MSG_CRTPPROOMANS";
  private final static String CREATE_ROOM_SUCCESS_ANSWER = "MSG_CRTROOMOKANS";
  private final static String ROOM_INVITATION = "MSG_ROOMINV";
  private final static String GET_ALL_DATAS_REQUEST = "MSG_GETALLDATASREQ";
  private final static String GET_ALL_DATAS_ANSWER = "MSG_GETALLDATASANS";
  private final static String GET_USER_FROM_NAME_REQUEST = "MSG_NAMETOUSERREQ";
  private final static String GET_USER_FROM_NAME_ANSWER = "MSG_NAMETOUSERANS";
  private final static String NEW_DATA_NOTIFICATION = "MSG_NEWDATANOT";
  private final static String LOG_OFF_NOTIFICATION = "MSG_LOGOFFNOT";
  private final static String GET_ROOM_FROM_NAME_REQUEST = "MSG_NAMETOROOMREQ";
  private final static String GET_ROOM_FROM_NAME_ANSWER = "MSG_NAMETOROOMANS";
  private final static String REJECTED_REQUEST = "MSG_REJECT";
  private final static String EMPTY_MESSAGE = "MSG_EMPTY";
  
  /**
   * Decode a message from the network
   * @requires reader not null
   * @param reader the net
   * @return the message read
   * @throws IOException 
   */
  public static Message retrieve(FrameReader reader) throws IOException {
    assert reader != null;
    
    String id = reader.readString();
    if (id == null || id.equals(EMPTY_MESSAGE)) {
      return new EmptyMessage();
    } else {
      Stalker client, destination;
      client = StalkerParser.retrieve(reader);
      destination = StalkerParser.retrieve(reader);
      assert client != null && destination != null;
      if (id.equals(ADD_DATA_REQUEST)) {
        return new AddDataRequest(client, destination, reader);
      } else if (id.equals(GET_LAST_DATA_REQUEST)) {
        return new GetLastDataRequest(client, destination, reader);
      } else if (id.equals(GET_LAST_DATA_ANSWER)) {
        return new GetLastDataAnswer(client, destination, reader);
      } else if (id.equals(REGISTER_REQUEST)) {
        return new RegisterRequest(client, destination, reader);
      } else if (id.equals(LOGIN_REQUEST)) {
        return new LoginRequest(client, destination, reader);
      } else if (id.equals(LOGIN_SUCCESS_ANSWER)) {
        return new LoginSuccessAnswer(client, destination, reader);
      } else if (id.equals(LOGIN_FAILED_ANSWER)) {
        return new LoginFailedAnswer(client, destination, reader);
      } else if (id.equals(CREATE_ROOM_REQUEST)) {
        return new CreateRoomRequest(client, destination, reader);
      } else if (id.equals(CREATE_PRIVATE_PERSISTENT_ROOM_REQUEST)) {
        return new CreatePrivatePersistentRoomRequest(client, destination, reader);
      } else if (id.equals(CREATE_ROOM_SUCCESS_ANSWER)) {
        return new CreateRoomSuccessAnswer(client, destination, reader);
      } else if (id.equals(ROOM_INVITATION)) {
        return new RoomInvitation(client, destination, reader);
      } else if (id.equals(GET_ALL_DATAS_REQUEST)) {
        return new GetAllDatasRequest(client, destination, reader);
      } else if (id.equals(GET_ALL_DATAS_ANSWER)) {
        return new GetAllDatasAnswer(client, destination, reader);
      } else if (id.equals(GET_USER_FROM_NAME_REQUEST)) {
        return new GetUserFromNameRequest(client, destination, reader);
      } else if (id.equals(GET_USER_FROM_NAME_ANSWER)) {
        return new GetUserFromNameAnswer(client, destination, reader);
      } else if (id.equals(NEW_DATA_NOTIFICATION)) {
        return new NewDataNotification(client, destination, reader);
      } else if (id.equals(LOG_OFF_NOTIFICATION)) {
        return new LogOffNotification(client, destination, reader);
      } else if (id.equals(GET_ROOM_FROM_NAME_REQUEST)) {
        return new GetRoomFromNameRequest(client, destination, reader);
      } else if (id.equals(GET_ROOM_FROM_NAME_ANSWER)) {
        return new GetRoomFromNameAnswer(client, destination, reader);
      } else if (id.equals(REJECTED_REQUEST)) {
        return new RejectedRequest(client, destination, reader);
      } else {
        assert false :
          "MessageParser: Unrecognized message id";
        return null;
      }
    }
  }
  
  /**
   * Encode a message to be sent over the network
   * @requires param not null
   * @param message the message
   * @param writer  the net
   * @throws IOException 
   */
  public static void send(Message message, FrameWriter writer) throws IOException {
    
    if (message instanceof AddDataRequest) {
      writer.writeString(ADD_DATA_REQUEST);
    } else if (message instanceof GetLastDataAnswer) {
      writer.writeString(GET_LAST_DATA_ANSWER);
    } else if (message instanceof GetLastDataRequest) {
      writer.writeString(GET_LAST_DATA_REQUEST);
    } else if (message instanceof RegisterRequest) {
      writer.writeString(REGISTER_REQUEST);
    } else if (message instanceof LoginRequest) {
      writer.writeString(LOGIN_REQUEST);
    } else if (message instanceof LoginSuccessAnswer) {
      writer.writeString(LOGIN_SUCCESS_ANSWER);
    } else if (message instanceof LoginFailedAnswer) {
      writer.writeString(LOGIN_FAILED_ANSWER);
    } else if (message instanceof CreateRoomRequest) {
      writer.writeString(CREATE_ROOM_REQUEST);
    } else if (message instanceof CreatePrivatePersistentRoomRequest) {
      writer.writeString(CREATE_PRIVATE_PERSISTENT_ROOM_REQUEST);
    } else if (message instanceof CreateRoomSuccessAnswer) {
      writer.writeString(CREATE_ROOM_SUCCESS_ANSWER);
    } else if (message instanceof RoomInvitation) {
      writer.writeString(ROOM_INVITATION);
    } else if (message instanceof GetAllDatasRequest) {
      writer.writeString(GET_ALL_DATAS_REQUEST);
    } else if (message instanceof GetAllDatasAnswer) {
      writer.writeString(GET_ALL_DATAS_ANSWER);
    } else if (message instanceof GetUserFromNameRequest) {
      writer.writeString(GET_USER_FROM_NAME_REQUEST);
    } else if (message instanceof GetUserFromNameAnswer) {
      writer.writeString(GET_USER_FROM_NAME_ANSWER);
    } else if (message instanceof NewDataNotification) {
      writer.writeString(NEW_DATA_NOTIFICATION);
    } else if (message instanceof LogOffNotification) {
      writer.writeString(LOG_OFF_NOTIFICATION);
    } else if (message instanceof GetRoomFromNameRequest) {
      writer.writeString(GET_ROOM_FROM_NAME_REQUEST);
    } else if (message instanceof GetRoomFromNameAnswer) {
      writer.writeString(GET_ROOM_FROM_NAME_ANSWER);
    } else if (message instanceof RejectedRequest) {
      writer.writeString(REJECTED_REQUEST);
    } else if (message instanceof EmptyMessage) {
      writer.writeString(EMPTY_MESSAGE);
      return;
    } else {
      assert false :
        "MessageParser: Unrecognized message";
    }
    StalkerParser.send(message.getClient(), writer);
    StalkerParser.send(message.getDestination(), writer);
    
    message.send(writer);
    
    writer.flush();
  }
  
}
